/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = rtp_comm.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2015/08/20 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <sys/time.h>

#include "frmem.h"
#include "frlog.h"
#include "frreport_comm.h"
#include "frct_comm.h"
#include "frexp_comm.h"

#include "rtp_core.h"
#include "rtp_comm.h"

static char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]

/*******************************************************************************
*  FUNC     :  释放内存
*  ARGS     :  pp_buffer
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void rtp_free(void **pp_buffer)
{
    if (pp_buffer == NULL || *pp_buffer == NULL)
        return;

    frfree(*pp_buffer);
    *pp_buffer = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  时间格式化成 2015-03-29 22:25:12.448671 的格式
*  ARGS     :  *p_tv                           (时间戳)
*           :  *p_time                         (buffer)
*           :  ui_time_size                    (buffer size)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __rtp_frtime2datetimestr(struct timeval *p_tv
                        , char *p_time
                        , unsigned int ui_time_size)
{
    struct tm *p_tm = NULL;

    if(p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time,ui_time_size,"%04d-%02d-%02d %02d:%02d:%02d.%06ld",
             p_tm->tm_year + 1900,p_tm->tm_mon + 1,p_tm->tm_mday,
             p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec,p_tv->tv_usec);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  时间转换
*  ARGS     :  *p_st_timestamp                     (时间戳)
*  RTN      :  转换后的时间值
*  NOTE     :
*******************************************************************************/
unsigned long rtp_get_timestamp(struct timeval *p_st_timestamp)
{
    return (unsigned long) (p_st_timestamp->tv_sec*1000000 + p_st_timestamp->tv_usec);
}

/*******************************************************************************
*  FUNC     :  打印时间
*  ARGS     :  st_timestamp                         (时间戳)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void rtp_print_timeval(struct timeval st_timestamp)
{
    char arr_buff[64];
    __rtp_frtime2datetimestr(&st_timestamp, arr_buff, sizeof(arr_buff));
    printf(":[%s]\n", arr_buff);
}

/*******************************************************************************
*  FUNC     :  格式化成十六进制字符串
*  ARGS     :  *p_inbuff    (输入的字符串)
*           :  i_len        (输入的字符串长度)
*           :  *p_outbuff   (格式化后的十六进制字符串)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void rtp_bin_to_hex_string(char *p_inbuff
                            , int i_len
                            , char *p_outbuff)
{
    int i_loop;
    char c;
    int i_used = 0;

    for (i_loop = 0; i_loop < i_len; i_loop++)
    {
        c = p_inbuff[i_loop];
        p_outbuff[i_used++] = hex_asc_hi(c);
        p_outbuff[i_used++] = hex_asc_lo(c);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  按一个字节打印十六进行字符串
*  ARGS     :  *p_buff  (char*字符串)
*           :  i_len   (字符串长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void rtp_print_hex_string(char *p_buff
                        , int i_len)
{
    int i_loop;

    for (i_loop = 0; i_loop < i_len; i_loop++)
        printf("%02x", p_buff[i_loop] & 0xFF);

    return;
}

FR_STATIC int __rtp_get_type_name(char *p_uri
                                , char **pp_type_name)
{
    char *p_pos = NULL;
    char *p_type_name = NULL;
    unsigned long ul_type_name_len;
    char *p_pos_at = NULL;

    if (p_uri == NULL)
        goto error;

    if ((p_pos = strstr(p_uri, "sip:")) == NULL)
        goto error;

    if ((p_pos_at = strchr(p_uri, '@')) != NULL)
        ul_type_name_len = p_pos_at - p_pos - strlen("sip:");
    else
        ul_type_name_len = strlen(p_uri) - strlen("sip:");

    if (ul_type_name_len <= 0)
        goto error;

    if ((p_type_name = (char *) frmalloc(sizeof(char) * (ul_type_name_len + 2))) == NULL)
    {
        RTP_MALLOCK_ERR;
        goto error;
    }
    memcpy(p_type_name, "'", 1);
    memcpy(p_type_name + 1, p_pos + strlen("sip:"), ul_type_name_len);
    p_type_name[ul_type_name_len + 1] = '\0';

    *pp_type_name = p_type_name;
    p_type_name = NULL;

    RTP_PRINT_CRIT("Request-URI type_name:[%s]\n", *pp_type_name);

    return FR_SUCC;
error:
    rtp_free((void **) &p_type_name);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  上报RTP信息
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_hash_report                        (数据上报)
*           :  ul_fbt                                   (第一帧的第一个包的时间)
*           :  ul_bytes                                 (第一帧的总字节数)
*           :  ul_ffft                                  (第一个完整帧的结束时间)
*           :  ul_ffpl                                  (第一个完整帧到达前丢失的包的个数)
*           :  p_i_analyze_ret                          (解析的返回值)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
void rtp_report(Conntrack *p_st_conn
                , Frhash_header *p_st_hash_report
                , unsigned long ul_fbt
                , unsigned long ul_bytes
                , unsigned long ul_ffft
                , unsigned long ul_pluff
                , int *p_i_analyze_ret)
{
    RTP_PRINT_INFO("rtp_report...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;
    Frlist_header *p_report_comm = NULL;
    Frlist_header *p_report_req = NULL;
    Frlist_header *p_lst_hdr = NULL;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field = NULL;
    long l_invite_time = 0L;
    char *p_title = NULL;
    char *p_type_name = NULL;

    p_lst_hdr = frexpect_get_param(p_st_conn);
    if (p_lst_hdr == NULL)
        return;

    p_st_node = FRLIST_FIRST_NODE(p_lst_hdr);
    while (p_st_node)
    {
        p_st_field = (Frvar_field *) FRLIST_GET_NODE_DATA(p_st_node);
        if (p_st_field->em_data_type == FRSTRING &&
                p_st_field->field_value.p_value != NULL)
        {
            if (strcmp(p_st_field->p_field_name, APM_SIP_INVITE_BEGIN_TIME) == 0)
                l_invite_time = atol(p_st_field->field_value.p_value);
            else if (strcmp(p_st_field->p_field_name, APM_SIP_INVITE_PLAY_URI) == 0)
            {
                rtp_free((void **) &p_title);
                if ((p_title = (char *) frmalloc(sizeof(char) * (strlen(p_st_field->field_value.p_value) + strlen("PLAY ") + 1))) == NULL)
                {
                    RTP_MALLOCK_ERR;
                    goto error;
                }
                snprintf(p_title, strlen(p_st_field->field_value.p_value) + strlen("PLAY ") + 1, "PLAY %s", p_st_field->field_value.p_value);
            }
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    if (l_invite_time == 0L || (unsigned long) l_invite_time > ul_fbt)
    {
        rtp_free((void **) &p_title);
        frexpect_free_param(&p_lst_hdr);
        return;
    }

    // 上报Request
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, FR_YES) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, l_invite_time / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, l_invite_time / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, 0) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, 0) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, p_title) != FR_SUCC)
        goto error;
    if (__rtp_get_type_name(p_title, &p_type_name) == FR_SUCC)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS ".type_name", p_type_name) != FR_SUCC)
            goto error;
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS ".type_code", p_type_name) != FR_SUCC)
            goto error;
        rtp_free((void **) &p_type_name);
    }
    p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body);
    p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body);

    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;
    *p_i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);

    // 上报Response
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;
    if (FRREPORT_BODY_L7LIST_SET_COMM(p_st_body, &p_report_comm) != FR_SUCC)
        goto error;
    if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_body, &p_report_req) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, ul_fbt / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_END_TIMESTAMP, ul_ffft / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_fbt - l_invite_time) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_ffft - ul_fbt) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_DATA_BYTES, ul_bytes) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_RTP_REPORT_RESP_PACKETS_LOST, ul_pluff) != FR_SUCC)
        goto error;
    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;
    *p_i_analyze_ret = APM_L7_ANALYZE_SET_RESP(*p_i_analyze_ret);

    rtp_free((void **) &p_title);
    frexpect_free_param(&p_lst_hdr);
    return;
error:
    *p_i_analyze_ret = APM_L7_ANALYZE_FAIL;
    rtp_free((void **) &p_title);
    rtp_free((void **) &p_type_name);
    frexpect_free_param(&p_lst_hdr);
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    frreport_body_l7list_free(&p_report_comm);
    frreport_body_l7list_free(&p_report_req);
    return;
}

/*******************************************************************************
*  FUNC     :  上报RTP响应信息，仅包含一部分内容，其他内容由collect补充
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_hash_report                        (数据上报)
*           :  ul_fbt                                   (第一帧的第一个包的时间)
*           :  ul_bytes                                 (第一帧的总字节数)
*           :  ul_ffft                                  (第一个完整帧的结束时间)
*           :  ul_ffpl                                  (第一个完整帧到达前丢失的包的个数)
*           :  p_i_analyze_ret                          (解析的返回值)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
void rtp_report_resp_only(Conntrack *p_st_conn
                        , Frhash_header *p_st_hash_report
                        , unsigned long ul_fbt
                        , unsigned long ul_bytes
                        , unsigned long ul_ffft
                        , unsigned long ul_pluff
                        , int *p_i_analyze_ret)
{
    RTP_PRINT_INFO("rtp_report_resp_only...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;

    // 上报Response
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, ul_fbt / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_END_TIMESTAMP, ul_ffft / 1000) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP"."APM_RTP_REPORT_MODULE_NAME".start_time", ul_fbt) != FR_SUCC)
    goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_ffft - ul_fbt) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_DATA_BYTES, ul_bytes) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_RTP_REPORT_RESP_PACKETS_LOST, ul_pluff) != FR_SUCC)
        goto error;
    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;
    *p_i_analyze_ret = APM_L7_ANALYZE_SET_RESP(*p_i_analyze_ret);

    return;
error:
    *p_i_analyze_ret = APM_L7_ANALYZE_FAIL;
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    return;
}

void rtp_init_detect_sess(Rtp_detect_session **pp_st_detect_sess)
{
    if (pp_st_detect_sess == NULL || *pp_st_detect_sess == NULL)
        return;

    memset(*pp_st_detect_sess, 0x00, sizeof(Rtp_detect_session));
    (*pp_st_detect_sess)->stream_type = APM_RTP_STREAM_TYPE_UNKNOWN;
    (*pp_st_detect_sess)->c_pre_is_marker = FR_NO;

    return;
}
